#ifndef BC_DYNAMICVALUE_HPP
#define BC_DYNAMICVALUE_HPP

#include "boundaryCondition.hpp"
#include "functionParserWrapper.hpp"
#include "solverBaseTypes_fwd.hpp"
#include "fieldMemberMacros.hpp"

namespace hms
{

using std::experimental::observer_ptr;

template<typename MeshType>
class DynamicValue : public BoundaryCondition<MeshType>
{
public:
	using BaseType = BoundaryCondition<MeshType>;
	using Type = typename BaseType::Type;
	using BaseType::field;
	using BaseType::patch;

private:
	bool m_isUniform;
	bool m_isFunction {false};
	std::vector<std::pair<scalar,ArrayXXs>> m_values;
	std::vector<FunctionParserWrapper> m_functions;
	mutable ArrayXs m_uniformFunctionBuf;

	observer_ptr<const Time> m_time {nullptr};

	Z_FIELD_MEMBER;

public:
	DynamicValue() = default;

	DynamicValue(
		Field<MeshType>&,
		const BoundaryPatch&,
		const Time&
	);

	DynamicValue(
		Field<MeshType>&,
		const BoundaryPatch&,
		const Time&,
		TimeSeries&&,
		bool isUniform
	);

	DynamicValue(
		Field<MeshType>&,
		const BoundaryPatch&,
		const Time&,
		std::vector<FunctionParserWrapper>&&,
		bool isUniform,
		const Field<MeshType>& z
	);

	virtual void update() const override;

	bool isUniform() const;
	bool isFunction() const;

	auto values() const -> const std::vector<std::pair<scalar,ArrayXXs>>&;
	void values( TimeSeries&&, bool isUniform );

	auto functions() const -> const std::vector<FunctionParserWrapper>&;
	void functions( std::vector<FunctionParserWrapper>&&, bool isUniform );

	auto time() const -> const Time&;
	void time( const Time& );

	Z_FIELD_ACCESSORS;

private:
	void update_function() const;
	void update_timeSeries() const;
	void isUniform(bool);
	void isFunction(bool);
};


/* maybe find a better place for this? Currently used in DynamicValue::update()
 * and vtk import for StaticValue */
template<typename MeshType>
void setPatchByFunction(
	Field<MeshType>&,
	const BoundaryPatch&,
	const Field<MeshType>& z,
	const Time&,
	const std::vector<FunctionParserWrapper>&
);
	
} // end namespace hms

#endif
